#!/usr/bin/env python3
# -*- coding:UTF-8 -*-
#-------------------------------------------------------------#
#装饰器
#装饰器是对象的功能扩展，比如函数，方法，类

#Python中一切皆是对象，对象具有属性。函数也是对象，函数也有属性 
#因此可以在函数内部创建函数，叫做内嵌函数

#内嵌函数在外部函数作用域内被正常使用，在外部函数作用域外无法使用。
#如果内嵌函数引用外部函数里定义的对象，那么此时内嵌函数叫做闭包函数

#闭包函数引用的外部定义变量叫做自由变量

#-------------------------------------------------------------#

# 1. 普通函数
def yunweinote(name):
    print(name)
yunweinote("yunweinote")

# 此时觉得普通函数功能单一，想要修改函数功能

# 2. 修改该函数
def yunweinote_01(name):
    print("My name is :"),
    print(name)
    age = 28
    print("My age is : %d" % age)
yunweinote_01("yunweinote")
#修改函数是Python编程规则不合理的方式,因此采用别的方式，比如函数调用

# 3.函数调用
def print_name():
    print("my name is :"),
def print_age(age):
    print("my age is %s" % age)
def yunweinote_02(name):
    print_name()
    print(name)
    print_age(28)
yunweinote_02("yunweinote")
#函数滴啊用存在同样的问题，当代码量或者要修改的地方很多时，全部都要调用会有很多重复代码
#因此需要一种不修改原函数的前提下，实现代码功能扩展，这就是装饰器的作用

#要了解装饰器(本质是函数)，就首先了解内嵌函数，闭包函数
# 4. 内嵌函数
def yunweinote_02():
    #print("hello,world")
    #name = "yunweinote_001"
    #age = 28
    #print(name)
    def yunweinote_03():
        name = "yunweinote_001"
        age = 28
        print("ok.I am in yuweinote_03")
        print("my name is %s" % name)
        print("my age is %d" % age)
    yunweinote_03()

yunweinote_02()

#总结：内嵌函数可以从外部函数获取参数，也可以不获取参数
# 3. 闭包函数

# 4. 装饰器
# 原函数，求和
def yunweinote_03(a,b):
    return a+b
#yunweinote_03(10,20)
print(yunweinote_03(10,20))
#定义装饰器
def new_decorator(pre): # 装饰器也是函数，因此存在内嵌
    def decorator(F): #定义装饰器名称，定义传入参数F
        def new_F(a,b): #定义新参数名称
            print(pre + "a is : %d",a) #功能扩展语句
            print(pre + "b is : %d",b)
            return F(a,b) #返回旧函数
        return new_F #返回新函数名
    return decorator

@new_decorator("ok,you input")
def yunweinote_03(a,b):
    return a + b
print(yunweinote_03(10,20))

@new_decorator("ok,you input")
def yunweinote_04(a,b):
    return a - b
print(yunweinote_04(200,100))
# 5. 函数装饰器
#如上述4,略
#总结：函数装饰器，传入函数名(对象),返回一个新的函数名(对象),在闭包函数中，增加功能模块.闭包函数旧函数，装饰器返回新函数名(对象)
#采用"@装饰器名" 方式进行调用装饰器，装饰器下面是要装饰的函数

# 6. 类方法装饰器
# 7. 类的装饰器
def decorator_class(Class):
    class newClass:

        def __init__(self,age):
            self.total_display = 0
            self.wrapped = Class(age) #旧类

        def display(self):
            self.total_display += 1
            print("total display",self.total_display)
            self.wrapped.display()

    return newClass
# 上述装饰器decorator_class，传入类名Class，返回newClass.装饰内容为，添加新的类属性,类的调用次数和打印

@decorator_class
class yunweinote_05:
    def __init__(self,age):
        self.age = age
    def display(self):
        print("my age is ",self.age)

liwl = yunweinote_05(28)
for i in range(3):
    liwl.display()